package main

import (
	"1119/grpc_demo/client"
	"1119/grpc_demo/helloworld"
	"context"
	"encoding/json"
	"github.com/golang/protobuf/jsonpb"
	"io"
	"log"
	"net"
	"net/http"
	"time"

	"github.com/gin-gonic/gin"
	"google.golang.org/grpc"
	"google.golang.org/grpc/reflection"
)

func init() {
	log.SetFlags(log.LstdFlags | log.Lshortfile)
}

type Service struct {
	helloworld.UnimplementedGreeterServer
}

func (tis *Service) SayHello(ctx context.Context, req *helloworld.HelloRequest) (*helloworld.HelloReply, error) {
	reqData, _ := json.MarshalIndent(req, "", "  ")
	log.Printf("SayHello: %v\n%v", req.String(), string(reqData))

	resp := &helloworld.HelloReply{Message: "hello " + req.GetName()}

	return resp, nil
}

func Server() {
	service := &Service{}
	svr := grpc.NewServer()
	helloworld.RegisterGreeterServer(svr, service)
	reflection.Register(svr)

	lis, err := net.ListenTCP("tcp4", &net.TCPAddr{
		Port: 6666,
	})
	if err != nil {
		log.Println(err)
		return
	}

	go svr.Serve(lis)
	defer svr.Stop()

	Client()
}

var (
	clients []*client.Stub
)

func Client() {

	cli := client.NewStub("127.0.0.1", 6666)
	if err := cli.Connect(context.TODO()); err != nil {
		log.Println(err)
		return
	}
	clients = append(clients, cli)

	serviceInfo := cli.GetServerInfo()
	if data, err := json.MarshalIndent(serviceInfo, "", "  "); err == nil {
		log.Println(string(data))
	}

	for _, service := range serviceInfo.Services {
		for _, method := range service.Methods {
			data, err := json.MarshalIndent(method.GetRequestJsonSchema(), "", "  ")
			log.Println(string(data), err)
			break
		}
	}

	req := &helloworld.HelloRequest{
		Name: "tina",
		Age:  22,
		Day:  helloworld.WeekDay_Saturday,
		Ss:   []int32{4, 5, 6, 7},
		StuList: []*helloworld.Student{
			{
				Name: "t",
				Age:  2,
			},
		},
	}
	if data, err := new(jsonpb.Marshaler).MarshalToString(req); err == nil {
		// 调用

		data = `{
  "age": 23,
  "day": "Friday",
  "name": "zl",
  "ss": [1, 2, 3],
  "stuList": [
    {
      "age": 22,
      "name": "tina"
    },
    {
      "age": 18,
      "name": "tony"
    }
  ]
}`
		resp, err := cli.InvokeRPC(context.TODO(), "helloworld.Greeter", "SayHello", data)
		log.Println(resp, err)
	}

	select {}
}

func main() {
	go Server()
	time.Sleep(time.Second)

	r := gin.Default()
	api := r.Group("/api")
	api.GET("/services", func(c *gin.Context) {
		var response []*client.JsonService
		for _, stub := range clients {
			response = append(response, stub.GetServerInfo().Services...)
		}

		c.JSON(http.StatusOK, response)
	})
	api.GET("/jsonSchema/:ServiceName/:MethodName", func(c *gin.Context) {
		serviceName := c.Param("ServiceName")
		methodName := c.Param("MethodName")

		log.Println(serviceName)
		log.Println(methodName)

		for _, stub := range clients {
			if objectMethod, ok := stub.GetServerInfo().GetMethod(serviceName, methodName); ok {
				schema := objectMethod.GetRequestJsonSchema()

				c.JSON(http.StatusOK, schema)
				return
			}
		}

		c.JSON(http.StatusNotFound, gin.H{})
	})
	api.POST("/invoke/:ServiceName/:MethodName", func(c *gin.Context) {
		serviceName := c.Param("ServiceName")
		methodName := c.Param("MethodName")

		body, err := io.ReadAll(c.Request.Body)
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{})
			return
		}

		log.Println(string(body))

		for _, stub := range clients {
			if _, ok := stub.GetServerInfo().GetMethod(serviceName, methodName); ok {
				if resp, err := stub.InvokeRPC(c.Request.Context(), serviceName, methodName, string(body)); err != nil {
					c.JSON(http.StatusInternalServerError, gin.H{})
				} else {
					var obj map[string]any
					_ = json.Unmarshal([]byte(resp), &obj)
					c.JSON(http.StatusOK, obj)
				}

				return
			}
		}

		c.JSON(http.StatusNotFound, gin.H{})
	})

	_ = r.Run(":3000")
}
